# vue和ext组件互相兼容使用方案
# 背景
目前控制器项目是vue做底座,嵌入ext页面的方案。
由于许多组件都是基于ext开发的,比如端口面板、端口选择、交换机选择器等等复杂组件,重新开发成本很大,于是想出一套两框架间组件能互相调用的方案
# vue中使用ext组件
目前新的表格页面中有个新增的表单,其中有端口组、选择交换机、短信通知等组件,是ext早就有的组件,如果重新开发成本巨大,于是决定这个新增弹窗使用ext去写。
那么vue中如何调用ext组件呢?
# 编写mgr
在ext中,页面通常由page、mgr构成,其中弹窗之类的都是写在mgr中,所以我们需要编写一个mgr去调用各弹窗组件。
结构通常如下:
export const Mgr = Ext.extend(SFX.mgr.GridMgr, {
initMgr: function () {},
actions: {},
createFormWindow: function () {},
});
# 调用
在actions中写好要使用的action后,编写一个调用函数:
import { Mgr } from "./Mgr";
export const openStrategyFrom = ({
id,
loadData,
}) => {
const mgr = new Mgr({
loadData,
});
mgr.executeAction(
{
id,
},
isNumber(id) ? "modify" : "add"
);
};
实例化刚才写的mgr后,通过executeAction
触发指定的action
,弹窗就能出现了。
注:前提是项目底层已加载ext源码,且处理好了弹窗层级关系。
vue页面通常只需传入一个成功的回调,在ext弹窗内部执行完业务后调用回调即可实现数据同步。
# ext中使用vue组件
# 无框架间交互
vue组件不需受ext控制时,处理起来就很简单
写一个容器,在其渲染完后,将vue组件通过createApp
+mount
挂载在ext的容器上即可。
{
xtype: 'box',
listeners: {
'afterrender': function () {
const id = this.id;
this.App = createApp(VueComponent, {});
this.App.mount('#' + id, true);
},
'destroy': function () {
this.JumpButtonApp?.unmount();
this.JumpButtonApp = null;
}
}
}
如果是纯展示的(只需要其渲染出html),通过h
及render
也是可以的。
# 框架间需要交互
这里以ext表单嵌入vue组件举例。
# ext容器
由于需要两框架间进行交互,我们需要先弄个ext容器,这里由于是表单中,便继承Ext.form.TriggerField
,这是为了触发ext的校验等操作,换普通box组件是没有这效果的。
同理,在渲染后,通过createApp
+mount
渲染vue组件,需要注意的是,要将ext原组件给覆盖渲染。
同时需配上:
setJsonValue:可以自己弄个字段去记录值,但是设置的时候不要忘了给当前ext设置一个值,不然校验会不通过
getJsonValue:返回记录的值即可
validate:手动调用vue组件去触发校验,不要忘了触发ext的原组件(弹错误路径)
onDestroy:销毁时需同步销毁
export const TerminalTypeCombo = Ext.extend(Ext.form.TriggerField, {
onRender: function (..._args) {
TerminalTypeCombo.superclass.onRender.apply(this, _args);
this.createTerminalTypeSelect();
},
createTerminalTypeSelect: function () {
me.terminalTypeSelectApp = createApp(TerminalTypeSelect, {
disabled,
value: me.jsonValue,
isFullPath: me.isFullPath,
fetchParams: me.fetchParams,
networkType: me.networkType,
allowBlank: me.allowBlank,
...me.props,
onSelect: (me.props?.onSelect || me.onSelect)?.bind(me),
});
// 强行覆盖在父元素内
me.terminalTypeSelect = me.terminalTypeSelectApp.mount(
me.el.dom.parentElement,
true
);
},
setJsonValue: function (v) {
},
getJsonValue: function () {
},
validate: function () {
this.terminalTypeSelect.checkValid();
return TerminalTypeCombo.superclass.validate.call(this);
},
onDestroy: function (..._args) {
TerminalTypeCombo.superclass.onDestroy.apply(this, _args);
this.terminalTypeSelectApp?.unmount();
},
});
# vue组件
vue组件相信大家都写的很熟练,ext所需要调用的方法都通过defineExpose
暴露出去即可。
处理起来比较麻烦的是校验状态的显示
用表单那一套处理起来很复杂,这里通过简单的办法实现。
<template>
<IxTooltip
:title="message"
:disabled="!message"
placement="topStart"
class="ix-form-item-message-tooltip">
<div class="terminal-type-select-wrap">
<IxsTreeSelect
:status="status">
</IxsTreeSelect>
</div>
</IxTooltip>
</template>
通过IxTooltip
包一下,记得添加class="ix-form-item-message-tooltip"
,红色的状态提示,与项目保持一致。
然后手动根据数据判断是否校验通过,如果没通过则将错误信息传给tooltip,同时给自己的组件设置正确的校验状态,即可实现校验的效果。
其它类型的组件处理起来也是同理,做一个中间层,解决数据、校验、销毁等的联通即可实现。
# 总结
实现框架间互相调用,可避免组件的重新开发,快速实现需求。